/**
 * elancom Corporation copy right 2012 - 2015  
 *   
 * $Header: https://192.168.1.224/svn/elancom/product/elancom-platform/trunk/src/main/java/com/elancom/framework/AppConfig.java 1109 2012-07-11 05:52:27Z xushuai $
 * $Id: AppConfig.java 1109 2012-07-11 05:52:27Z xushuai $
 * $Author: xushuai $
 * $Date: 2012-07-11 13:52:27 +0800 (周三, 11 七月 2012) $
 * $Revision: 1109 $
 */
package com.elancom.framework.config;

import java.util.HashMap;
import java.util.Map;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.VisitorSupport;
import org.dom4j.io.SAXReader;
import org.dom4j.tree.DefaultElement;

/**
 * @author elancom
 * @date 2012-6-26
 */
public final class AppConfig {
	private String id;
	private static String sessionContextFactory;
	private final Map<String, Module> moduleMapping = new HashMap<String, Module>();
	private static AppConfig appConfig = new AppConfig();

	/**
	 * @return the sessionContextFactory
	 */
	public static String getSessionContextFactory() {
		return sessionContextFactory;
	}
	/**
	 * @param sessionContextFactory
	 *            the sessionContextFactory to set
	 */
	static void setSessionContextFactory(String sessionContextFactory) {
		AppConfig.sessionContextFactory = sessionContextFactory;
	}

	static {
		try {
			parseAppConfig();
		} catch (final DocumentException e) {
			e.printStackTrace();
			throw new RuntimeException("初始化应用配置失败");
		}
	}

	public static String getId() {
		return appConfig.id;
	}

	public static Module getModule(String moduleCode) {
		return AppConfig.appConfig.moduleMapping.get(moduleCode);
	}

	private static void initID(final Document document) {
		final DefaultElement idElment = (DefaultElement) document.selectObject("/appConfig/id");
		appConfig.id = idElment.getTextTrim();
	}

	private static void initModules(final Document document) {
		final DefaultElement modulesElement = (DefaultElement) document.selectObject("/appConfig/modules");
		modulesElement.accept(new VisitorSupport() {
			public StringBuilder pPath = new StringBuilder();

			private String buildParentPath(Element node) {
				final Element parent = node.getParent();
				if ("module".equals(parent.getName())) {
					final Attribute codeAttr = parent.attribute("code");

					if (codeAttr != null) {
						String code = codeAttr.getValue();
						if (code != null && !(code = code.trim()).isEmpty()) {
							if (pPath.length() != 0) {
								pPath.insert(0, ".");
							}
							pPath.insert(0, code);
						}
						buildParentPath(parent);
					} else {
						throw new RuntimeException("module's code can't be null.");
					}
				}
				return pPath.toString();

			}

			private void resetPath() {
				pPath.delete(0, pPath.length());
			}

			@Override
			public void visit(Element node) {
				final Attribute codeAttr = node.attribute("code"), nameAttr = node.attribute("name");

				if (codeAttr != null && "module".equals(node.getName())) {
					String code = codeAttr.getValue();
					final String name = nameAttr.getValue();

					if (code != null && !(code = code.trim()).isEmpty()) {
						final Module module = new Module();
						module.setCode(code);
						module.setName(name);

						resetPath();
						buildParentPath(node);

						// parent
						if (pPath.length() > 0) {
							final Module moduleParent = AppConfig.appConfig.moduleMapping.get(pPath.toString());
							if (moduleParent != null) {
								module.setParent(moduleParent);
								moduleParent.addChild(module);
							} else {
								throw new RuntimeException("[" + code + "," + name + "]'s" + " parent module can't find");
							}
							pPath.append(".");
						}

						// mapping
						AppConfig.appConfig.moduleMapping.put(pPath.append(code).toString(), module);
					}
				}
			}
		});
	}

	private static void parseAppConfig() throws DocumentException {
		final SAXReader reader = new SAXReader();
		final String webClasses = Thread.currentThread().getContextClassLoader().getResource("/").getPath();
		String webInfo = webClasses.substring(0, webClasses.length() - "classes/".length());
		final Document document = reader.read(webInfo += "elancom.xml");

		initID(document);
		initModules(document);
	}
}
